#include "utTimingArc.h"
#include "parser_helper.h"
#include "message.h"
#include <cassert>

typedef pair<int,double> IDX_FACTOR;
//----------------------------------------------------------------------------------------------------------//
pair<unsigned int,double> utTimingArc_C::calcIterpolattionFactor(const vector<double>& p_rvIndices,double p_dVal)
{
    double dFactor(0);
    unsigned int idx(0);
    vector<double>::size_type sz = p_rvIndices.size();
    for(idx=0;idx<sz-1;idx++) {
        if((idx==0 && p_rvIndices[idx]>p_dVal)                          //p_dVal: too small
            || (p_rvIndices[idx+1]>p_dVal && p_rvIndices[idx]<=p_dVal)  //        in range
            || (idx==sz-2 && p_rvIndices[idx+1]<=p_dVal)){              //        too large
            break;
        }
    }
    dFactor = (p_dVal-p_rvIndices[idx])/(p_rvIndices[idx+1]-p_rvIndices[idx]);
    assert(dFactor<1e5);
    assert(idx>=0 && idx<=sz-1);
    return make_pair(idx,dFactor);
}
//----------------------------------------------------------------------------------------------------------//
double utTimingArc_C::interpolateLUT(const LibParserLUT& p_rLUT,double p_dInputTrans,double p_dLoad)
{
    //DebugMsg("in interpolation\n");
    //uint32_t i,j;
    //double tran_factor=0.0;
    //double load_factor=0.0;
    double d11,d12,d21,d22;
    
    //trans idx
    IDX_FACTOR IDX_FACTOR_tran = utTimingArc_C::calcIterpolattionFactor(p_rLUT.transitionIndices,p_dInputTrans);
    IDX_FACTOR IDX_FACTOR_load = utTimingArc_C::calcIterpolattionFactor(p_rLUT.loadIndices,p_dLoad);
    double tran_factor = IDX_FACTOR_tran.second;
    double load_factor = IDX_FACTOR_load.second;
    uint32_t j = IDX_FACTOR_tran.first;
    uint32_t i = IDX_FACTOR_load.first;
    /*
    vector<double>::size_type szj = p_rLUT.transitionIndices.size();
    for(j=0;j<szj-1;j++) {
        //cout<<"dbg:: "<<i<<" "<<p_dInputTrans<<" "<<p_rLUT.transitionIndices[i]<<endl;
        if(j==0 && p_rLUT.transitionIndices[j]>p_dInputTrans){ //extrapolation for too small trans
            tran_factor = (p_dInputTrans-p_rLUT.transitionIndices[j])/(p_rLUT.transitionIndices[j+1]-p_rLUT.transitionIndices[j]);
            break;
        } else if(p_rLUT.transitionIndices[j+1]>p_dInputTrans && //interpolation
            p_rLUT.transitionIndices[j]<=p_dInputTrans) {
            tran_factor = (p_dInputTrans-p_rLUT.transitionIndices[j])/(p_rLUT.transitionIndices[j+1]-p_rLUT.transitionIndices[j]);
            break;
        } else if(j==szj-2 && p_rLUT.transitionIndices[j+1]<p_dInputTrans){ //extrapolation for too large trans
            tran_factor = (p_dInputTrans-p_rLUT.transitionIndices[j])/(p_rLUT.transitionIndices[j+1]-p_rLUT.transitionIndices[j]);
            //break;
        }
    }

    //load idx
    vector<double>::size_type szi = p_rLUT.loadIndices.size();
    for(i=0;i<szi-1;i++){
        if(p_rLUT.loadIndices[i+1]>p_dLoad &&
            p_rLUT.loadIndices[i]<=p_dLoad) {
            load_factor = (p_dLoad-p_rLUT.loadIndices[i])/(p_rLUT.loadIndices[i+1]-p_rLUT.loadIndices[i]);
            break;
        }
    }
    */

    double val = 0.0;
    //if ( (i<szi-1) && (j<szj-1) ) {
        d11 = p_rLUT.tableVals[i][j];
        d12 = p_rLUT.tableVals[i+1][j];
        d21 = p_rLUT.tableVals[i][j+1];
        d22 = p_rLUT.tableVals[i+1][j+1];

        val = (d11*(1-load_factor)*(1-tran_factor)+
            d12*(1-tran_factor)*load_factor+
            d21*(1-load_factor)*tran_factor+
            d22*load_factor*tran_factor);
    //} else {
    //    if ((i==szi-1) && (j<szj-1)) {
    //        d11 = p_rLUT.tableVals[i][j];
    //        d21 = p_rLUT.tableVals[i][j+1];
    //        val = d11+(d21-d11)*tran_factor;
    //    } else if ((i<szi-1) && (j==szj-1)) {
    //        d11 = p_rLUT.tableVals[i][j];
    //        d12 = p_rLUT.tableVals[i+1][j];
    //        val = d11+(d12-d11)*load_factor;
    //    } else {
    //        val = p_rLUT.tableVals[i][j];
    //    }
    //}

#ifdef LIB_DEBUG
    InfoMsg("tran=%.3f idx=%d factor=%f\n",p_dInputTrans,IDX_FACTOR_tran.first,IDX_FACTOR_tran.second);
    InfoMsg("load=%.3f idx=%d factor=%f\n",p_dLoad,IDX_FACTOR_load.first,IDX_FACTOR_load.second);
    cout <<"[interpolation]" <<"transition "<<p_dInputTrans<<" index="<<j<<" ("<<p_rLUT.transitionIndices[j]<<
    ","<<p_rLUT.transitionIndices[j+1]<<")"<<endl;

    cout<<"[interpolation]" <<"load "<<p_dLoad<<" index="<<i<<" ("<<p_rLUT.loadIndices[i]<<
    ","<<p_rLUT.loadIndices[i+1]<<")"<<endl;

    cout<<"[interpolation]" <<"("<<d11<<","<<d21<<")"<<endl;
    cout<<"[interpolation]" <<"("<<d12<<","<<d22<<")"<<endl;
    cout<<"[interpolation]" <<val<<endl;
#endif
    return val;
}
//----------------------------------------------------------------------------------------------------------//

